﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using Microsoft.Win32;


namespace FreeX
{
    /// <summary>
    /// Provides an encapsulation of a number of system file-info classes
    /// </summary>
    public sealed class FreeXFileInfo
    {

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="thePath"></param>
        public FreeXFileInfo(string thePath)
        {
            m_FilePath = thePath;
            fi = new FileInfo(thePath);
            fvi = FileVersionInfo.GetVersionInfo(thePath);
        }

        #region Members
        private string m_FilePath;
        private FileInfo fi;
        private FileVersionInfo fvi;

        /// <summary>
        /// Defines unit to represent file size
        /// </summary>
        public enum FileSizeFormat
        {
            /// <summary>
            /// Size in bytes
            /// </summary>
            [DescriptionAttribute("Size in bytes")]
            Bytes,
            /// <summary>
            /// Size in kilobytes
            /// </summary>
            [DescriptionAttribute("Size in kilobytes")]
            Kb,
            /// <summary>
            /// Size in megabytes
            /// </summary>
            [DescriptionAttribute("Size in megabytes")]
            Mb,
            /// <summary>
            /// Size in gigabytes
            /// </summary>
            [DescriptionAttribute("Size in gigabytes")]
            Gb,
            /// <summary>
            /// calculates size to what it feels is the most logical unit
            /// </summary>
            [DescriptionAttribute("Automatically adjust units based on size")]
            Auto
        }

        #endregion

        #region Properties

        /* File Properties */
        /// <summary>
        /// Large icon for file type as specified in shell
        /// </summary>
        public Icon AssociatedIconLarge
        {
            get
            {
                return IconExtractor.IconHandler.IconFromExtensionShell(Path.GetFileName(m_FilePath), IconExtractor.IconSize.Large);
            }
        }

        /// <summary>
        /// Small icon for file type as specified in shell
        /// </summary>
        public Icon AssociatedIconSmall
        {
            get
            {
                return IconExtractor.IconHandler.IconFromExtensionShell(Path.GetFileName(m_FilePath), IconExtractor.IconSize.Small);
            }
        }

        /// <summary>
        /// Name of file without the full path. includes extension
        /// </summary>
        public string Filename
        {
            get
            {
                return Path.GetFileName(m_FilePath);
            }
        }

        /// <summary>
        /// The file extension for the current object
        /// </summary>
        public string FileExtension
        {
            get
            {
                return Path.GetExtension(m_FilePath);
            }
        }

        /// <summary>
        /// Read only field representing files creation date
        /// </summary>
        public DateTime DateCreated
        {
            get
            {
                return fi.CreationTime;
            }
            set
            {
                fi.CreationTime = value;

            }
        }

        /// <summary>
        ///  Read only field representing files Last Access date
        /// </summary>
        public DateTime DateLastAccessed
        {
            get
            {
                return fi.LastAccessTime;
            }
            set
            {
                    fi.LastAccessTime = value;
            }
        }

        /// <summary>
        ///  Read only field representing the date the file was last modified
        /// </summary>
        public DateTime DateModified
        {
            get
            {
                return fi.LastWriteTime;
            }
            set
            {
                    fi.LastWriteTime = value;
            }
        }

        /// <summary>
        /// The registry string associated with the current files type
        /// </summary>
        public string FileType
        {
            get
            {
                return GetFileTypeString(Path.GetExtension(m_FilePath));
            }
        }

        /// <summary>
        /// The files associated description, if available
        /// </summary>
        public string Description
        {
            get
            {
                return fvi.FileDescription;
            }
        }

        /// <summary>
        /// The files associated comments, if available
        /// </summary>
        public string Comments
        {
            get
            {
                return fvi.Comments;
            }
        }

        /// <summary>
        /// The files associated copyright, if available
        /// </summary>
        public string Copyright
        {
            get
            {
                return fvi.LegalCopyright;
            }
        }

        /// <summary>
        /// The specific attributes of the current file, specified as a string
        /// </summary>
        public string Attributes
        {
            get
            {
                return GetAttributeString();
            }
        }

        /* Image File Properties */
        /// <summary>
        /// Raw calculated filesize. Available only for image files
        /// </summary>
        public double RawFileSize
        {
            get
            {
                return m_FilePath.Length;
            }
        }

        /// <summary>
        ///  The height of the specified image file.
        /// </summary>
        public int Height
        {
            get
            {
                return Image.FromFile(m_FilePath).Height;
            }
        }

        /// <summary>
        /// The width of the specified image file.
        /// </summary>
        public int Width
        {
            get
            {
                return Image.FromFile(m_FilePath).Width;
            }
        }

        /// <summary>
        /// The vertical resolution of the specified image file.
        /// </summary>
        public float VerticalResolution
        {
            get
            {
                return Image.FromFile(m_FilePath).VerticalResolution;
            }
        }

        /// <summary>
        /// The horizontal resolution of the specified image file.
        /// </summary>
        public float HorizontalResolution
        {
            get
            {
                return Image.FromFile(m_FilePath).HorizontalResolution;
            }
        }

        /// <summary>
        /// The image format for the specified file
        /// </summary>
        public ImageFormat RawFormat
        {
            get
            {
                return Image.FromFile(m_FilePath).RawFormat;
            }
        }

        /// <summary>
        /// The physical dimensions of the image file
        /// </summary>
        public SizeF PhysicalDimension
        {
            get
            {
                return Image.FromFile(m_FilePath).PhysicalDimension;
            }
        }


        /*   TODO Audio and video files
                    Attributes,
                    Author,
                    Owner,
                    Title,

                    Artist,
                    [Description("Album Title")]
                    AlbumTitle,
                    Subject,
                    Category,
                    Pages,
                    Status,
                    Year,
                    [Description("Track Number")]
                    TrackNumber,
                    Genre,
                    Duration,
                    BitRate
        */

        #endregion

        #region Public Methods

        /// <summary>
        /// Calculates size of file
        /// </summary>
        /// <param name="theUnits">A FileSizeFormat constant specifying the desired format string</param>
        /// <returns>returns a formatted string with the file size in the requested units</returns>
        public string GetFormattedFileSize(FileSizeFormat theUnits)
        {
            string fileSize;
            double rawFileSize;

            switch (theUnits)
            {
                case FileSizeFormat.Bytes:
                    fileSize = m_FilePath.Length.ToString("###.##;;0");
                    break;
                case FileSizeFormat.Kb:
                    rawFileSize = m_FilePath.Length / 1024;
                    fileSize = rawFileSize.ToString("###.##");
                    break;
                case FileSizeFormat.Mb:
                    rawFileSize = (float)m_FilePath.Length / 1048576;
                    fileSize = rawFileSize.ToString("###.##");
                    break;
                case FileSizeFormat.Gb:
                    rawFileSize = (float)m_FilePath.Length / 1073741824;
                    fileSize = rawFileSize.ToString("###.##");
                    break;
                case FileSizeFormat.Auto:
                    fileSize = CalcSizeAuto();
                    break;
                default:
                    /* Send as bytes */
                    fileSize = m_FilePath.Length.ToString("###.##;;0") + " b";
                    break;
            }

            return fileSize;
        }

        /// <summary>
        /// Sets Creation, Last Access and Last Write Time dates to now
        /// </summary>
        /// <returns>The date that was used</returns>
        public DateTime Touch()
        {
            var now = DateTime.Now;
            File.SetCreationTime(m_FilePath, now);
            File.SetLastAccessTime(m_FilePath, now);
            File.SetLastWriteTime(m_FilePath, now);
            return now;
        }

        /// <summary>
        /// Deletes current file
        /// </summary>
        /// <returns>0 if successful, 1 if delete fails</returns>
        public int Delete()
        {
            fi.Delete();

            /* check for failure */
            return fi.Exists ? 1 : 0;

        }

        /// <summary>
        /// Determines if the item exists in the specified location
        /// </summary>
        /// <returns>true if item exist, false if not</returns>
        public bool Exists()
        {
            return fi.Exists;
        }

        #endregion

        #region private methods

        private string CalcSizeAuto()
        {
            double fileSz = (double)m_FilePath.Length / 1024;
            String fileSizeStr;

            if (fileSz < 1)
            {
                fileSizeStr = m_FilePath.Length.ToString("###.##;;0") + " B";
            }
            else if (fileSz > 1048576)
            {
                fileSz = (float)m_FilePath.Length / 1073741824;
                fileSizeStr = fileSz.ToString("###.##") + " GB";
            }
            else if (fileSz > 1024)
            {
                fileSz = (float)m_FilePath.Length / 1048576;
                fileSizeStr = fileSz.ToString("###.##") + " MB";
            }

            else
            {
                fileSizeStr = fileSz.ToString("###.##") + " KB";
            }

            return fileSizeStr;
        }

        /// <summary> 
        /// Goes through registry to get the file type description for each extension 
        /// </summary> 
        /// <param name="theExtension"></param> 
        /// <returns></returns> 
        private static string GetFileTypeString(String theExtension)
        {
            // HKEY_CLASSES_ROOT // 
            var root = Registry.ClassesRoot;

            // something like '.csproj' 
            var openValue = root.OpenSubKey(theExtension);

            try
            {
                if (openValue != null)
                {
                    // This will get the name of a key - something like 'VisualStudio.csproj.8.0' 
                    var val = openValue.GetValue("").ToString();
                    // So we go there to get the value // 
                    var typeVal = root.OpenSubKey(val);
                    // something like 'Visual C# Project file' 
                    return typeVal.GetValue("").ToString();

                }

               // Sometimes its unrecognized // 
               return theExtension;
            }
            //Sometimes the default key value is Null...no big deal 
            catch (Exception)
            {
                return theExtension;
            }

        }

        private string GetAttributeString()
        {
            string attrString = string.Empty;

            if (fi.Attributes == FileAttributes.Hidden)
            {
                attrString += "H";
            }

            if (fi.Attributes == FileAttributes.ReadOnly)
            {
                attrString += "R";
            }

            if (fi.Attributes == FileAttributes.System)
            {
                attrString += "S";
            }

            return attrString;
        }

        #endregion


    }
}
